﻿using System;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RAP.Framework.Libary.Configuration;
using RAP.Framework.Libary.DataSource;
using RAP.Framework.Libary.DomTemplateBuilder;
using RAP.Framework.Libary.ServerCacheManager;
using RAP.Framework.Libary.SqlDataService.Service;
using RAP.Framework.Libary.Utils;
using RAP.Web.Libary.Common;
using RAP.Web.Libary.Common.Model;
using RAP.Web.Libary.Common.Model.Log;
using RAP.Web.Libary.Common.Model.Session;
using RAP.Web.Libary.Config;
using RAP.Web.Libary.Controller.Filters;
using RAP.Web.Libary.Service;
using RAP.Web.Libary.Service.DataService;
using ConfigurationManager = RAP.Framework.Libary.Configuration.ConfigurationManager;

namespace RAP.Web.Libary.AppStatup
{
  /// <summary>
  /// 服务启动基类，继承自StartupBase
  /// </summary>
  public class StartupAppBase : IStartupApp
	{
    #region 属性
    /// <summary>
    /// 服务的本地跟路径
    /// </summary>
    public string ServerRootPath { get; set; } = "/Server/";

		/// <summary>
		/// 配置文件的根路径
		/// </summary>
		public string ConfigPath { get; set; } = "~/Server/Configs/";

		/// <summary>
		/// 
		/// </summary>
		public IConfiguration Configuration { get; protected set; }

		/// <summary>
		/// 
		/// </summary>
		public Type SiteSettingType { get; set; }

		/// <summary>
		/// 
		/// </summary>
		public Type CacheManagerType { get; set; } = typeof( CacheManager );

		/// <summary>
		/// /
		/// </summary>
		public Type SqlDataServiceType { get; set; } = typeof( SqlDataService );

		/// <summary>
		/// 
		/// </summary>
		public Type LogParamsType { get; set; } = typeof( LogParams );
    #endregion

    /// <summary>
    /// 
    /// </summary>
    /// <param name="configuration"></param>
    public StartupAppBase( IConfiguration configuration )
		{
			Configuration = configuration;
		}

		/// <summary>
		/// 配置依赖注入的服务
		/// </summary>
		/// <param name="services"></param>
		public virtual void ConfigureServices( IServiceCollection services )
		{
			services.AddCors();
			ConfigureFilters( services );

			services.AddSingleton( ConfigurationManager.AppSettings );

			services.AddSingleton( typeof( ICacheManager ), CacheManagerType );

			services.AddTransient( typeof( ISqlDataService ), SqlDataServiceType );

			services.AddScoped( typeof( ILogParams ), LogParamsType );

			ConfigureUserSession( services );

			services.InitServices<IAPIService>();

			services.AddMvc().AddRazorOptions( opts =>
			{
				ConfiguerRazorViewOptions( opts );
			} ).AddRazorPagesOptions( opts =>
			{
				ConfiguerRazorPagesOptions( opts );
			} );
		}

		/// <summary>
		/// 配置Razo引擎的参数
		/// </summary>
		/// <param name="opts"></param>
		protected virtual void ConfiguerRazorViewOptions( RazorViewEngineOptions opts )
		{
			var viewSuffix = RazorViewEngine.ViewExtension;
			var formats = opts.ViewLocationFormats;

			formats.Clear();
			formats.Add( $"{ServerRootPath}Views/{{1}}/{{0}}{viewSuffix}" );
			formats.Add( $"{ServerRootPath}Views/Shared/{{0}}{viewSuffix}" );
			//formats.Add( $"{ServerRootPath}Pages/{{0}}{viewSuffix}" );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="opts"></param>
		protected virtual void ConfiguerRazorPagesOptions( RazorPagesOptions opts )
		{
			opts.RootDirectory = $"{ServerRootPath}Pages";
		}

		/// <summary>
		/// 配置Http Filter
		/// </summary>
		/// <param name="services"></param>
		public virtual void ConfigureFilters( IServiceCollection services )
		{
      //注册自定义的Filter
      services.AddMvc( config =>
			{
				config.Filters.Add( new QueryParamsFilter() );
				config.Filters.Add( new NeedSessionFilter() );
				config.Filters.Add( new HasMenuPowerFilter() );
				config.Filters.Add( new HasDataPowerFilter() );
				config.Filters.Add( new JSONResultFilter() );
			} );
		}

		/// <summary>
		/// 配置流水日志
		/// </summary>
		/// <param name="app"></param>
		/// <param name="services"></param>
		/// <param name="loggerFactory"></param>
		/// <returns></returns>
		public virtual ILogger ConfigureLogger( IApplicationBuilder app, IServiceProvider services, ILoggerFactory loggerFactory )
		{
			var logger = loggerFactory.CreateLogger( "Startup" );

			return logger;
		}

		/// <summary>
		/// 配置HttpHeader
		/// </summary>
		/// <param name="app"></param>
		/// <param name="services"></param>
		public virtual void ConfigureHttpHeaders( IApplicationBuilder app, IServiceProvider services )
		{
			app.UseCors( builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod() );

			app.UseForwardedHeaders( new ForwardedHeadersOptions
			{
				ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
			} );
		}

		/// <summary>
		/// 配置开发环境的参数
		/// </summary>
		/// <param name="app"></param>
		/// <param name="env"></param>
		/// <param name="services"></param>
		/// <param name="configuration"></param>
		/// <param name="logger"></param>
		protected virtual void ConfigureDevelopment(
			IApplicationBuilder app,
			IWebEnvironment env,
			IServiceProvider services,
			IConfigurationManager configuration,
			ILogger logger )
		{
			
			app.UseDeveloperExceptionPage();

			//初始化开发环境配置管理
			app.UseConfiguration( $"{ConfigPath}SiteConfig/Config.dev.json" );
		}

		/// <summary>
		/// 配置生产环境的参数
		/// </summary>
		/// <param name="app"></param>
		/// <param name="env"></param>
		/// <param name="services"></param>
		/// <param name="configuration"></param>
		/// <param name="logger"></param>
		protected virtual void ConfigureProduction(
			IApplicationBuilder app,
			IWebEnvironment env,
			IServiceProvider services,
			IConfigurationManager configuration,
			ILogger logger )
		{
			//生产环境不能返回错误详细信息
			app.UseExceptionHandler( ( iapp ) =>
			{
				iapp.Run( async ( context ) =>
				{
					var ex = context.Features.Get<IExceptionHandlerFeature>()?.Error;
					//记录错误日志
					//todo...
					logger.LogError( ex.Message );
					//返回500错误
					await context.Response.WriteAsync( ServiceResult.CreateErrorResult( "内部服务错误！", 500 ).ToString() );
				} );
			} );

			//初始化生产环境配置管理
			app.UseConfiguration( $"{ConfigPath}SiteConfig/Config.pro.json" );
		}

		/// <summary>
		/// 自定义配置
		/// </summary>
		/// <param name="app"></param>
		/// <param name="env"></param>
		/// <param name="services"></param>
		/// <param name="configuration"></param>
		/// <param name="logger"></param>
		protected virtual void CustomerConfigure(
			IApplicationBuilder app,
			IWebEnvironment env,
			IServiceProvider services,
			IConfigurationManager configuration,
			ILogger logger )
		{
      if ( RuntimeInformation.IsOSPlatform( OSPlatform.Windows ) )
			{
        //设置应用程序根路径
        RAP.Framework.Libary.Utils.Extensions.APP_ROOT_PATH = env.ContentRootPath;
			}
			DataSourceHelper.AllowDebug = true;

			ConfigureSiteSettings( app, env, services, configuration );
			
			if ( env.IsDevelopment )
			{
				//配置开发环境参数
				ConfigureDevelopment( app, env, services, configuration, logger );
			}
			else
			{
				//配置生产环境参数
				ConfigureProduction( app, env, services, configuration, logger );
			}
			LoadSiteSettings( configuration );

			if ( !DebugApp( configuration ) )
			{
				throw new Exception( "程序被终止！" );
			}

			//初始化模板配置
			app.UseDomTemplate( $"{ConfigPath}TSql/Configures.config" );

			//文档模板调试事件，可在该事件中中断后跟踪模板执行
			DomTemplateManager.OnErrorEvent += new Action<IDictionary>( ( err ) =>
			{
				Console.WriteLine( $"数据查询错误：{err.ToJSON()}" );
			} );

			DataSourceHelper.OnError += new Action<IDictionary>( ( err ) =>
			{
				//数据查询服务出错时，在此处中断查看错误信息
				Console.WriteLine( $"数据查询错误：{err.ToJSON()}" );
			} );

			ConfigureMVC( app, env, services );

			//初始化数据查询服务
			SqlDataService.Initialize( app, logger );
		}

		/// <summary>
		/// 配置站点参数服务
		/// </summary>
		/// <param name="app"></param>
		/// <param name="env"></param>
		/// <param name="services"></param>
		/// <param name="configuration"></param>
		protected virtual void ConfigureSiteSettings(
			IApplicationBuilder app,
			IWebEnvironment env,
			IServiceProvider services,
			IConfigurationManager configuration )
		{
			//初始化基础配置，不区分环境
			app.UseConfiguration( $"{ConfigPath}SiteConfig/Config.json" );
		}

		/// <summary>
		/// 读取站点配置
		/// </summary>
		/// <param name="configuration"></param>
		protected virtual void LoadSiteSettings( IConfigurationManager configuration )
		{
			//初始化站点参数对象
			SiteSettingsBase.LoadSettings( configuration, SiteSettingType );
		}

		/// <summary>
		/// 配置用户回话对象服务
		/// </summary>
		/// <param name="services"></param>
		protected virtual void ConfigureUserSession( IServiceCollection services )
		{
			services.AddTransient( typeof( IUserSession ), typeof( UserSessionBase ) );
		}

		/// <summary>
		/// 配置MVC
		/// </summary>
		/// <param name="app"></param>
		/// <param name="env"></param>
		/// <param name="services"></param>
		protected virtual void ConfigureMVC(
			IApplicationBuilder app,
			IWebEnvironment env,
			IServiceProvider services )
		{
			app.UseMvc( routes =>
			{
				routes.MapRoute( "default", "{controller}/{action}", new { action = "Index", controller = "Home" } );
			} );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="app"></param>
		/// <param name="env"></param>
		/// <param name="services"></param>
		/// <param name="configuration"></param>
		/// <param name="loggerFactory"></param>
		protected virtual void Configure(
			IApplicationBuilder app,
			IWebEnvironment env,
			IServiceProvider services,
			IConfigurationManager configuration,
			ILoggerFactory loggerFactory )
		{
			var logger = ConfigureLogger( app, services, loggerFactory );

			ConfigureHttpHeaders( app, services );

			CustomerConfigure( app, env, services, configuration, logger );
		}

		/// <summary>
		/// 调试WebAPP
		/// </summary>
		/// <param name="configuration"></param>
		/// <returns></returns>
		public virtual bool DebugApp( IConfigurationManager configuration )
		{
			Console.WriteLine( $"\r\n当前进程Id：{Process.GetCurrentProcess().Id}。" );
			if ( configuration.ToBoolean( "IsDebug" ) )
			{
				if ( !Console.IsInputRedirected )
				{
					Console.WriteLine( "是否继续？(Y/N)" );
					var needContinue = Console.ReadKey();
					Console.WriteLine();
					if ( needContinue.Key == ConsoleKey.N )
					{
						return false;
					}

					Console.WriteLine( "是否准备调试？(Y/N)" );
					var needDebug = Console.ReadKey();
					Console.WriteLine();
					if ( needDebug.Key == ConsoleKey.Y )
					{
						var counter = 30;
						Console.Write( $"等待调试，倒计时" );
						var cursorPos = new { x = Console.CursorLeft, y = Console.CursorTop };
						while ( counter > 0 )
						{
							Console.SetCursorPosition( cursorPos.x, cursorPos.y );
							Console.Write( $"{counter}s..." );
							Thread.Sleep( 999 );
							counter--;
						}
						Console.SetCursorPosition( cursorPos.x, cursorPos.y );
						Console.WriteLine( "" );
					}
				}
			}
			return true;
		}
	}
}
